package com.TexasHoldem;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.protobuf.ProtobufDecoder;
import io.netty.handler.codec.protobuf.ProtobufEncoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.handler.timeout.ReadTimeoutHandler;
import io.netty.handler.traffic.ChannelTrafficShapingHandler;
import io.netty.handler.traffic.GlobalTrafficShapingHandler;
import io.netty.util.HashedWheelTimer;
import io.netty.util.Timer;

import java.io.IOException;
import java.math.BigInteger;
import java.net.UnknownHostException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.MissingResourceException;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

import org.apache.commons.dbutils.DbUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.ScalarHandler;
import org.apache.log4j.Logger;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jmx.export.annotation.ManagedAttribute;
import org.springframework.jmx.export.annotation.ManagedOperation;
import org.springframework.jmx.export.annotation.ManagedResource;


import com.TexasHoldem.RpcInterface.rpc.TexasHoldemService;
import com.TexasHoldem.RpcInterface.rpc.TexasHoldemService.BetRequest;
import com.TexasHoldem.RpcInterface.rpc.TexasHoldemService.EnterTableRequest;
import com.TexasHoldem.RpcInterface.rpc.TexasHoldemService.EnterTableResponse;
import com.TexasHoldem.RpcInterface.rpc.TexasHoldemService.GetTableListRequest;
import com.TexasHoldem.RpcInterface.rpc.TexasHoldemService.GetTableListResponse;
import com.TexasHoldem.RpcInterface.rpc.TexasHoldemService.Heart;
import com.TexasHoldem.RpcInterface.rpc.TexasHoldemService.LeaveTableRequest;
import com.TexasHoldem.RpcInterface.rpc.TexasHoldemService.LoginRequest;
import com.TexasHoldem.RpcInterface.rpc.TexasHoldemService.LoginSucessResponse;
import com.TexasHoldem.RpcInterface.rpc.TexasHoldemService.NotifyMsg;
import com.TexasHoldem.RpcInterface.rpc.TexasHoldemService.PlayerData;
import com.TexasHoldem.RpcInterface.rpc.TexasHoldemService.PlayersList;
import com.TexasHoldem.RpcInterface.rpc.TexasHoldemService.QuestRequest;
import com.TexasHoldem.RpcInterface.rpc.TexasHoldemService.RegRequest;
import com.TexasHoldem.RpcInterface.rpc.TexasHoldemService.Response;
import com.TexasHoldem.RpcInterface.rpc.TexasHoldemService.TableConfgData;
import com.TexasHoldem.RpcInterface.rpc.TexasHoldemService.TableRoomInfo;
import com.TexasHoldem.RpcInterface.rpc.TexasHoldemService.TexasHoldem.BlockingInterface;
import com.TexasHoldem.ServerData.PokerPlayer;
import com.TexasHoldem.ServerData.RoomTableData;
import com.TexasHoldem.ServerData.TableData;
import com.TexasHoldem.ServerData.Quest.PokerQuest;
import com.TexasHoldem.ServerData.Quest.PokerQuestRule;
import com.TexasHoldem.ServerData.Quest.QuestData;
import com.TexasHoldem.ServerData.Quest.ServerPlayersQuestRun;
import com.TexasHoldem.core.CashTable;
import com.TexasHoldem.core.MTTTable;
import com.TexasHoldem.core.Player;
import com.TexasHoldem.core.Table;
import com.TexasHoldem.core.TableConfig;
import com.TexasHoldem.core.TableType;
import com.TexasHoldem.core.ZoomTable;
import com.TexasHoldem.core.actions.Action;
import com.TexasHoldem.core.actions.BetAction;
import com.TexasHoldem.core.actions.RaiseAction;
import com.TexasHoldem.db.TexasHoldemDB;
import com.TexasHoldem.util.ResourceBundleConfig;
import com.TexasHoldem.util.SpringFactory;
import com.TexasHoldem.xSocket.data.CommonConstants;
import com.google.protobuf.BlockingRpcChannel;
import com.google.protobuf.RpcController;
import com.google.protobuf.ServiceException;
import com.googlecode.protobuf.socketrpc.RpcChannels;
import com.googlecode.protobuf.socketrpc.RpcForwarder;
import com.googlecode.protobuf.socketrpc.SocketRpcController;
import com.googlecode.protobuf.socketrpc.SocketRpcProtos;




@ManagedResource()
public class TexasHoldemServerEx implements com.TexasHoldem.RpcInterface.rpc.TexasHoldemService.TexasHoldem.BlockingInterface,com.TexasHoldem.RpcInterface.rpc.TexasHoldemService.TexasHoldemManage.BlockingInterface,ITexasHoldemZoomInterface,ITexasHoldemInterface
{
	private static final Logger logger = Logger.getLogger(TexasHoldemServerEx.class);
	
	 /** Table type (betting structure). */
    private static final TableType TABLE_TYPE = TableType.NO_LIMIT;

    /** The size of the big blind. */
    private static final int BIG_BLIND = 10;
    
    /** The starting cash per player. */
    private static final int STARTING_CASH = 50000;
    
    private Map<String, Player> players =  null;
    
	//扑克桌子
	private Map<Integer,Table> cashtablelist = new HashMap<Integer,Table>();
	private Map<Integer,Table> zoomtablelist = new HashMap<Integer,Table>();
	private Map<Integer,Table> mtttablelist = new HashMap<Integer,Table>();
	private Map<Integer,Table> tablelist = null;
	
	private ConcurrentLinkedQueue<Player> freePlayer = new ConcurrentLinkedQueue<Player>();
	

	private boolean shutdowned;
	
	private long starttime = System.currentTimeMillis();
	
	
	//在线玩家
	private Map<Long,PokerPlayer> onlineplayers = new HashMap<Long,PokerPlayer>();
	
	private final AtomicLong ids = new AtomicLong(0);
	
	private PokerQuestRule pokerquestrule = new PokerQuestRule();
	
	private ServerPlayersQuestRun serverplayersquestrun = new ServerPlayersQuestRun(onlineplayers);;

	
	public PokerQuestRule getPokerquestrule()
	{
		return pokerquestrule;
	}
	public ResourceBundleConfig getConfig() {
		return ResourceBundleConfig.getInstance();
	}
	private static ExecutorService executeService;
	
	// 德州扑克实现逻辑的服务
	private final RpcForwarder rpcTexasHoldemService = new RpcForwarder();
	
	// 德州扑克大厅实现逻辑的服务
	private final RpcForwarder rpcTexasHoldemManageService = new RpcForwarder();
	
	private Map<PokerPlayer,Channel>  clientchannel = new HashMap<PokerPlayer,Channel>();
	
	private Map<PokerPlayer,Channel>  disconnectclientchannel = new HashMap<PokerPlayer,Channel>();
	
	public static TexasHoldemServerEx instance = null;
	
	
	public final GlobalTrafficShapingHandler counter = new GlobalTrafficShapingHandler(Executors.newScheduledThreadPool(1), 1000);
	
	private final AtomicLong pokerids = new AtomicLong();
	
	private double netreadspeed = 0;
	private long cumulativeReadBytes = 0;
	private double netwritespeed = 0;
	private long cumulativeWrittenBytes = 0;
	
	public long getPokerids() {
		return pokerids.addAndGet(1);
	}
	/**
	 * @throws InterruptedException
	 * 初始化牌桌房间服务器
	 */
	
	public void InitNet() throws InterruptedException
	{
		EventLoopGroup bossGroup = new NioEventLoopGroup(); // (1)
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        
        
        
        
        try {
            ServerBootstrap b = new ServerBootstrap(); // (2)
            b.group(bossGroup, workerGroup)
             .channel(NioServerSocketChannel.class) // (3)
             .childHandler(new ChannelInitializer<SocketChannel>() { // (4)
                 @Override
                 public void initChannel(SocketChannel ch) throws Exception {
                	 ch.pipeline().addLast("GLOBAL_TRAFFIC_SHAPING", counter);
                	 //ch.pipeline().addLast("readTimeoutHandler",new ReadTimeoutHandler(30));
                     ch.pipeline().addLast("frameDecoder", new ProtobufVarint32FrameDecoder());
                     ch.pipeline().addLast("protobufDecoder", new ProtobufDecoder(SocketRpcProtos.ProtocolMessage.getDefaultInstance()));
                     
                     ch.pipeline().addLast("frameEncoder", new ProtobufVarint32LengthFieldPrepender());
                     ch.pipeline().addLast("protobufEncoder", new ProtobufEncoder());
                	 ch.pipeline().addLast("ping", new TexasHoldemHeartHandle(30, 30, 20));
                     ch.pipeline().addLast("handler", new TexasHoldemHandler(rpcTexasHoldemService));

                     
                     
                 }
             })
             .option(ChannelOption.SO_BACKLOG, 128)          // (5)
             .childOption(ChannelOption.SO_KEEPALIVE, true); // (6)
    
            rpcTexasHoldemService.registerBlockingService(TexasHoldemService.TexasHoldem.newReflectiveBlockingService(this));
            //rpcForwarder.registerService(TexasHoldemService.TexasHoldem.newReflectiveService(new TexasHoldemServiceImpl()));
            //rpcForwarder.registerService(TexasHoldemService.TexasHoldem.newReflectiveService(new TexasHoldemServiceImpl()));
            
            Executors.newScheduledThreadPool(1).scheduleAtFixedRate(new Runnable() {
				
				@Override
				public void run() {
					// TODO Auto-generated method stub
					if(getInstance().cumulativeReadBytes > 0)
						getInstance().netreadspeed = getInstance().counter.trafficCounter().cumulativeReadBytes() - getInstance().cumulativeReadBytes;
					getInstance().cumulativeReadBytes = getInstance().counter.trafficCounter().cumulativeReadBytes();
					
					if(getInstance().cumulativeWrittenBytes > 0)
						getInstance().netwritespeed = getInstance().counter.trafficCounter().cumulativeWrittenBytes() - getInstance().cumulativeWrittenBytes;
					getInstance().cumulativeWrittenBytes = getInstance().counter.trafficCounter().cumulativeWrittenBytes();
					
						
				}
			}, 1,  1, TimeUnit.SECONDS);
            
            // Bind and start to accept incoming connections.
            ChannelFuture f = b.bind(1818).sync(); // (7)
    
            // Wait until the server socket is closed.
            // In this example, this does not happen, but you can do that to gracefully
            // shut down your server.
            f.channel().closeFuture().sync();
        } finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
	}
	/**
	 * @throws InterruptedException
	 * 初始大厅服务器，负责管理房间服务器
	 */
	
	public void InitHallNet() throws InterruptedException
	{
		EventLoopGroup bossGroup = new NioEventLoopGroup(); // (1)
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap(); // (2)
            b.group(bossGroup, workerGroup)
             .channel(NioServerSocketChannel.class) // (3)
             .childHandler(new ChannelInitializer<SocketChannel>() { // (4)
                 @Override
                 public void initChannel(SocketChannel ch) throws Exception {
                     ch.pipeline().addLast("frameDecoder", new ProtobufVarint32FrameDecoder());
                     ch.pipeline().addLast("protobufDecoder", new ProtobufDecoder(SocketRpcProtos.ProtocolMessage.getDefaultInstance()));
                     
                     ch.pipeline().addLast("frameEncoder", new ProtobufVarint32LengthFieldPrepender());
                     ch.pipeline().addLast("protobufEncoder", new ProtobufEncoder());
                       
                     ch.pipeline().addLast("handler", new TexasHoldemHandler(rpcTexasHoldemManageService));
                 }
             })
             .option(ChannelOption.SO_BACKLOG, 128)          // (5)
             .childOption(ChannelOption.SO_KEEPALIVE, true); // (6)
    
            rpcTexasHoldemManageService.registerBlockingService(TexasHoldemService.TexasHoldemManage.newReflectiveBlockingService(this));
            //rpcForwarder.registerService(TexasHoldemService.TexasHoldem.newReflectiveService(new TexasHoldemServiceImpl()));
            //rpcForwarder.registerService(TexasHoldemService.TexasHoldem.newReflectiveService(new TexasHoldemServiceImpl()));
            
            // Bind and start to accept incoming connections.
            ChannelFuture f = b.bind(1919).sync(); // (7)
    
            // Wait until the server socket is closed.
            // In this example, this does not happen, but you can do that to gracefully
            // shut down your server.
            f.channel().closeFuture().sync();
        } finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
	}
	public void InitTable()
	{
		players = new HashMap<String, Player>();
		
		int cashtablecount = Integer.parseInt(getConfig().getProperty("cashtablecount"));
		int zoomtablecount = Integer.parseInt(getConfig().getProperty("zoomtablecount"));
		int mtttablecount = Integer.parseInt(getConfig().getProperty("mtttablecount"));
		
		boolean onlyzoom = Boolean.parseBoolean(getConfig().getProperty("onlyzoom"));
		boolean onlycash = Boolean.parseBoolean(getConfig().getProperty("onlycash"));
		boolean onlymtt = Boolean.parseBoolean(getConfig().getProperty("onlymtt"));
		
		
		executeService = Executors.newFixedThreadPool(Integer.parseInt(getConfig().getProperty("workthreadcount")));
        
		for(int i = 0;i < cashtablecount;i++)
		{
			TableConfig tableconfig = new TableConfig();
			tableconfig.setId(i + 1);
			Table t = new CashTable(tableconfig);
			t.setZoomInterface(this);
			t.setServerinterface(this);
			this.cashtablelist.put(i + 1, t);
			executeService.execute(t);
		}
		for(int i = 0;i < zoomtablecount;i++)
		{
			TableConfig tableconfig = new TableConfig();
			tableconfig.setId(i + 1);
			Table t = new ZoomTable(tableconfig);
			t.setZoomInterface(this);
			t.setServerinterface(this);
			this.zoomtablelist.put(i + 1, t);
			executeService.execute(t);
		}
		for(int i = 0;i < mtttablecount;i++)
		{
			TableConfig tableconfig = new TableConfig();
			tableconfig.setId(i + 1);
			Table t = new MTTTable(tableconfig);
			t.setZoomInterface(this);
			t.setServerinterface(this);
			this.mtttablelist.put(i + 1, t);
			executeService.execute(t);
		}
		executeService.execute(this.serverplayersquestrun);
		if(onlyzoom)
			tablelist = zoomtablelist;
		if(onlycash)
			tablelist = cashtablelist;
		if(onlymtt)
			tablelist = mtttablelist;
	}
	public void InitQuest()
	{
		pokerquestrule.Init();
	}
	public void run() throws InterruptedException, IOException
	{
		this.InitQuest();
		this.InitTable();
		this.InitNet();
	}
	
	@ManagedAttribute(description = "获取当前牌桌数量")
	public int getTableCount()
	{
		return this.cashtablelist.size() + this.mtttablelist.size() + this.zoomtablelist.size();
	}
	@ManagedAttribute(description = "获取当前服务器网络情况")
	public String getServerNetInfo ()
	{
		return "当前读:" + this.counter.trafficCounter().currentReadBytes() + "," + 
		"当前写:" + this.counter.trafficCounter().currentReadBytes() + "," +
		"累积读:" + this.counter.trafficCounter().cumulativeReadBytes() + "," +
		"累积写:" + this.counter.trafficCounter().cumulativeWrittenBytes() + "," +
		"速度rw(b/s):" + this.netreadspeed + "," + this.netwritespeed;
	}
	@ManagedAttribute(description = "获取在线玩家数")
	public int getTalbePlayers()
	{
		int count = 0;
		for(Table t:this.cashtablelist.values())
		{
			count += t.getPlayersCount();
		}
		for(Table t:this.mtttablelist.values())
		{
			count += t.getPlayersCount();
		}
		for(Table t:this.zoomtablelist.values())
		{
			count += t.getPlayersCount();
		}
		return count;
	}
	@ManagedAttribute(description = "获取在线玩家所以cash")
	public String getTablePlayerCash()
	{
		String playerscash = "";
		long allcash = 0;
		for(Table t:this.cashtablelist.values())
		{
			if(t.getPlayersCount() > 0)
				playerscash += t.toString();
			
			allcash+=t.getPlayerAllCash();
		}
		playerscash += "\n";
		for(Table t:this.mtttablelist.values())
		{
			if(t.getPlayersCount() > 0)
				playerscash += t.toString();
			
			allcash+=t.getPlayerAllCash();
		}
		playerscash += "\n";
		for(Table t:this.zoomtablelist.values())
		{
			if(t.getPlayersCount() > 0)
				playerscash += t.toString();
			
			allcash+=t.getPlayerAllCash();
		}
		return playerscash + ",allcash:" + allcash;
	}
	
	@ManagedAttribute(description = "获取各个牌桌运行时间")
	public String getTableRunTime()
	{
		String tabletimeinfo = "";
		for(Table t:this.cashtablelist.values())
		{
			tabletimeinfo += "Cash_" + t.getTableCofing().getId() + ":" + t.getAllruntime() + ",";
		}
		tabletimeinfo += "\n";
		for(Table t:this.mtttablelist.values())
		{
			tabletimeinfo += "Mtt_" + t.getTableCofing().getId() + ":" + t.getAllruntime() + ",";
		}
		tabletimeinfo += "\n";
		for(Table t:this.zoomtablelist.values())
		{
			tabletimeinfo += "Zoom_" +t.getTableCofing().getId() + ":" + t.getAllruntime() + ",";
		}
		return tabletimeinfo;
	}
	
	@ManagedAttribute(description = "运行时间")
	public String getRuningTime()
	{
		long diff = System.currentTimeMillis() - this.starttime;
		long diffSeconds = diff / 1000 % 60;
        long diffMinutes = diff / (60 * 1000) % 60;
        long diffHours = diff / (60 * 60 * 1000) % 24;
        long diffDays = diff / (24 * 60 * 60 * 1000);

        
		return diffDays + "天 " + diffHours + ":" + diffMinutes + ":" + diffSeconds;
	}
	
	@ManagedAttribute(description = "获取玩家统计信息")
	public String getPlayerStatistic()
	{
		StringBuilder stat = new StringBuilder();
		for (PokerPlayer pokerplayer : this.clientchannel.keySet()) {
			stat.append(pokerplayer.getName() + "[");
			stat.append(pokerplayer.getStatistics());
			stat.append("],\n");
		}
		return stat.toString();
	}
	
	public static TexasHoldemServerEx getInstance() {
		return instance;
	}
	
	public static ResourceBundleConfig getInstanceConfig() {
		return getInstance().getConfig();
	}
	
	public static void main(String[] args) throws UnknownHostException, IOException, InterruptedException
	{
		SpringFactory.init(new ClassPathXmlApplicationContext(new String[] {"beanRefConfigurer.xml", "beanRefJMXServer.xml"}));
		
		
		instance = (TexasHoldemServerEx) SpringFactory.getBean("texasholdemserverex");
		SpringFactory.register(instance, "Server","TexasHoldemServerEx");
		SpringFactory.startJmxHttpAdaptor();
		getInstance().run();
	}
	
	public TexasHoldemServerEx() {
		super();
	}
	public long verifyToken(String name,String toke,SocketRpcController rpc) {
		// TODO Auto-generated method stub
		long id = ids.incrementAndGet();
		
		final PokerPlayer p = new PokerPlayer(id);
		p.Init();
		p.setName(name);
		p.getStatistics().getLoginTime().set(System.currentTimeMillis());
		reg(name,"123456");

		clientchannel.put(p,rpc.getChannel());
		onlineplayers.put(id, p);
		p.setClientchannel(rpc.getChannel());
		p.LoginInfo(rpc.getChannel());
		
		return id;
	}
	
	public int reg(String account, String password) {
		// TODO Auto-generated method stub
		Connection c = TexasHoldemDB.getDBConnUitl().GetConnection();
		QueryRunner qr = new QueryRunner();
		String sql = "insert into pokerplayer (account, password) values (?, ?)";
	    try {
	        int count = qr.update(c, sql, account,password);
	        BigInteger newId = (BigInteger) qr.query(c, "select last_insert_id()", new ScalarHandler<BigInteger>(1));
	    } catch (SQLException e) {
	        e.printStackTrace();
	    }
	    finally
	    {
	    	DbUtils.closeQuietly(c);
	    }
		return 1;
	}
	
	public RoomTableData getRoomTables() {
		// TODO Auto-generated method stub
		List<TableData> l = new ArrayList<TableData>();
		for(Table t:this.cashtablelist.values())
		{
			TableData tb = new TableData();
			tb.setBigBlind(t.getTableCofing().getBigBlind());
			tb.setTablename("澳门新豪天地");
			tb.setTabletype("No Limit");
			l.add(tb);
		}
		for(Table t:this.zoomtablelist.values())
		{
			TableData tb = new TableData();
			tb.setBigBlind(t.getTableCofing().getBigBlind());
			tb.setTablename("澳门新豪天地");
			tb.setTabletype("No Limit");
			l.add(tb);
		}
		for(Table t:this.mtttablelist.values())
		{
			TableData tb = new TableData();
			tb.setBigBlind(t.getTableCofing().getBigBlind());
			tb.setTablename("澳门新豪天地");
			tb.setTabletype("No Limit");
			l.add(tb);
		}
		RoomTableData r = new RoomTableData();
		r.setList(l);
		r.setIp(getConfig().getProperty("server_ip"));
		r.setPort(getConfig().getProperty("server_port"));
		return r;
	}
	
	public PokerPlayer findbychannel(Channel c)
	{
		for (Entry<PokerPlayer, Channel> entry : this.clientchannel.entrySet()) {
			if (entry.getValue().equals(c)) {
				return entry.getKey();
			}
		}
		return null;
	}
	public int PlayerEnterTable(EnterTableRequest request,SocketRpcController rpc) 
	{
		// TODO Auto-generated method stub
		if(this.clientchannel.containsValue(rpc.getChannel()))
		{
			if(request.getTableid() != 0)
			{
				Table t = tablelist.get(request.getTableid());
				if(t != null && t.getPlayersCount() < t.getTableCofing().getLimitPlayerCount())
				{
					PokerPlayer p = findbychannel(rpc.getChannel());
					if(p !=null && !p.getCurplaytable().containsKey(t.getTableCofing().getId()))
					{
						//下发玩家更新信息意见移动到牌桌table
						Player player = new Player(p.getName(), t.getTableCofing().getBigBlind() * 100, p);
						t.addPlayer(player);
						p.AddPlayerInTable(player, t.getTableCofing().getId());

						this.logger.debug(player.getName() + ",PlayerEnterTable:" + t.getTableCofing().getId());
					}
					
				}

				
				return 1;
			}
			else
			{
				
			}
		}
		return 0;
	}
	
	public int playerAutoEnterTable(EnterTableRequest request,SocketRpcController rpc) {
		// TODO Auto-generated method stub
		
		Table freetable = null;
		synchronized (this.tablelist)
		{
			for(Table t:this.tablelist.values())
			{
				if(t.getPlayersCount() < t.getTableCofing().getLimitPlayerCount())
				{
					freetable = t;
					break;
				}
			}
		}
		PokerPlayer p = findbychannel(rpc.getChannel());
		
		if(freetable != null && !p.getCurplaytable().containsKey(freetable.getTableCofing().getId()))
		{
			//下发玩家更新信息意见移动到牌桌table
			
			Player player = new Player(p.getName(), freetable.getTableCofing().getBigBlind() * 100, p);
			
			if(request.hasPos())
				player.setPos(request.getPos());
			
			freetable.addPlayer(player);
			p.AddPlayerInTable(player, freetable.getTableCofing().getId());
			this.logger.debug(player.getName() + ",playerAutoEnterTable:" + freetable.getTableCofing().getId());
			
			
			return 1;
		}
		return 0;
		
	}
	
	public int playerLeaveTable(long tableid, SocketRpcController rpc) {
		// TODO Auto-generated method stub
		
		
		PokerPlayer p = findbychannel(rpc.getChannel());
		if(p.getCurplaytable() != null)
		{
			Player player = p.getCurplaytable().get(tableid);
			if(player != null && this.tablelist.containsKey(tableid))
				this.tablelist.get(tableid).removePlayer(player);
			
			this.tablelist.get(tableid).notifyPlayerLeaveTable(player);
			
			return 1;
		}
		return 0;
	}
	
	public int betAction(int tableid, int type, int amount,
			SocketRpcController rpc) {
		// TODO Auto-generated method stub
		
		
		
		PokerPlayer p = this.findbychannel(rpc.getChannel());
		
		if(type == TexasHoldemService.BetRequest.BET_ACTION.ALL_IN_VALUE)
		{
			if(p.getCurplaytable().containsKey(tableid))
			{
				Player player = p.getCurplaytable().get(tableid);
				player.setAction(Action.ALL_IN);
				synchronized (player) 
				{
					player.notifyAll();
			    }
			}
		}
		else if(type == TexasHoldemService.BetRequest.BET_ACTION.BET_VALUE)
		{
			if(p.getCurplaytable().containsKey(tableid))
			{
				Player player = p.getCurplaytable().get(tableid);
				player.setAction( new BetAction(amount));
				synchronized (player) 
				{
					player.notifyAll();
			    }
			}
		}
		else if(type == TexasHoldemService.BetRequest.BET_ACTION.CALL_VALUE)
		{
			if(p.getCurplaytable().containsKey(tableid))
			{
				Player player = p.getCurplaytable().get(tableid);
				player.setAction(Action.CALL);
				synchronized (player) 
				{
					player.notifyAll();
			    }
			}
		}
		else if(type == TexasHoldemService.BetRequest.BET_ACTION.CHECK_VALUE)
		{
			if(p.getCurplaytable().containsKey(tableid))
			{
				Player player = p.getCurplaytable().get(tableid);
				player.setAction( Action.CHECK);
				synchronized (player) 
				{
					player.notifyAll();
			    }
			}
		}
		else if(type == TexasHoldemService.BetRequest.BET_ACTION.FOLD_VALUE)
		{
			if(p.getCurplaytable().containsKey(tableid))
			{
				Player player = p.getCurplaytable().get(tableid);
				player.setAction( Action.FOLD);
				synchronized (player) 
				{
					player.notifyAll();
			    }
			}
		}
		else if(type == TexasHoldemService.BetRequest.BET_ACTION.RAISE_VALUE)
		{
			if(p.getCurplaytable().containsKey(tableid))
			{
				
				Player player = p.getCurplaytable().get(tableid);
				player.setAction( new RaiseAction(amount));
				synchronized (player) 
				{
					player.notifyAll();
			    }
			}
		}
		else if(type == TexasHoldemService.BetRequest.BET_ACTION.SMALL_BLIND_VALUE)
		{
			if(p.getCurplaytable().containsKey(tableid))
			{
				Player player = p.getCurplaytable().get(tableid);
				player.setAction( Action.SMALL_BLIND);
				synchronized (player) 
				{
					player.notifyAll();
			    }
			}
		}
		else if(type == TexasHoldemService.BetRequest.BET_ACTION.BIG_BLIND_VALUE)
		{
			if(p.getCurplaytable().containsKey(tableid))
			{
				Player player = p.getCurplaytable().get(tableid);
				player.setAction( Action.BIG_BLIND);
				synchronized (player) 
				{
					player.notifyAll();
			    }
			}
		}
		else if(type == TexasHoldemService.BetRequest.BET_ACTION.CONTINUE_VALUE)
		{
			if(p.getCurplaytable().containsKey(tableid))
			{
				Player player = p.getCurplaytable().get(tableid);
				player.setAction( Action.CONTINUE);
				synchronized (player) 
				{
					player.notifyAll();
			    }
			}
		}
		return 0;
	}
	@Override
	public LoginSucessResponse login(RpcController controller,
			LoginRequest request) throws ServiceException {
		// TODO Auto-generated method stub
		long playerid = this.verifyToken(request.getName(),request.getToken(),(SocketRpcController)controller);
		LoginSucessResponse.Builder res = LoginSucessResponse.newBuilder();
		res.setId(playerid);
		
		return res.build();
	}
	@Override
	public Response reg(RpcController controller, RegRequest request)
			throws ServiceException {
		// TODO Auto-generated method stub
		int ret = this.reg(request.getAccount(),request.getPassword());
		com.TexasHoldem.RpcInterface.rpc.TexasHoldemService.Response.Builder r =  com.TexasHoldem.RpcInterface.rpc.TexasHoldemService.Response.newBuilder();
		
		r.setRetcode(ret);
		return r.build();
	}
	@Override
	public GetTableListResponse getRoomTableData(RpcController controller,
			GetTableListRequest request) throws ServiceException {
		// TODO Auto-generated method stub
		RoomTableData r = this.getRoomTables();
		GetTableListResponse.Builder tr = GetTableListResponse.newBuilder();
		for(TableData t:r.getList())
		{
			TableRoomInfo.Builder tb = TableRoomInfo.newBuilder();
			tb.setRoomIp(r.getIp());
			tb.setRoomName("test room");
			tb.setRoomPort(r.getPort());
			tb.setTableid(t.getTableid());
			tb.setBigBlind(t.getBigBlind());
			tr.getRoomlistList().add(tb.build());
		}
		return tr.build();
	}
	@Override
	public EnterTableResponse playerEnterTable(RpcController controller,
			EnterTableRequest request) throws ServiceException {
		// TODO Auto-generated method stub
		int retcode = this.PlayerEnterTable(request,(SocketRpcController)controller);
		EnterTableResponse.Builder b = EnterTableResponse.newBuilder();
		b.setStatus(retcode);
		return b.build();
	}
	@Override
	public EnterTableResponse playerAutoEnterTable(RpcController controller,
			EnterTableRequest request) throws ServiceException {
		// TODO Auto-generated method stub
		int retcode = this.playerAutoEnterTable(request,(SocketRpcController)controller);
		EnterTableResponse.Builder b = EnterTableResponse.newBuilder();
		b.setStatus(retcode);
		return b.build();
	}
	@Override
	public Response playerLeaveTable(RpcController controller,
			LeaveTableRequest request) throws ServiceException {
		// TODO Auto-generated method stub
		
		return null;
		
	}
	@Override
	public Response betAction(RpcController controller, BetRequest request)
			throws ServiceException {
		// TODO Auto-generated method stub
		int ret = this.betAction(request.getTableid(), request.getBetaction().getNumber(), request.getAmount(), (SocketRpcController)controller);
		com.TexasHoldem.RpcInterface.rpc.TexasHoldemService.Response.Builder r =  com.TexasHoldem.RpcInterface.rpc.TexasHoldemService.Response.newBuilder();
		
		r.setRetcode(ret);
		return r.build();
	}
	
	@Override
	public GetTableListResponse getTableLisInfo(RpcController controller,
			TableConfgData request) throws ServiceException {
		// TODO Auto-generated method stub
		RoomTableData r = this.getRoomTables();
		GetTableListResponse.Builder tr = GetTableListResponse.newBuilder();
		for(TableData t:r.getList())
		{
			TableRoomInfo.Builder tb = TableRoomInfo.newBuilder();
			tb.setRoomIp(r.getIp());
			tb.setRoomName("test room");
			tb.setRoomPort(r.getPort());
			tb.setTableid(t.getTableid());
			tb.setBigBlind(t.getBigBlind());
			tr.getRoomlistList().add(tb.build());
		}
		return tr.build();
		
	}
	@Override
	public Response tableStart(RpcController controller, TableConfgData request)
			throws ServiceException {
		// TODO Auto-generated method stub
		if(this.tablelist.containsKey(request.getTableid()))
			this.tablelist.get(request.getTableid()).setBstart(true);
		com.TexasHoldem.RpcInterface.rpc.TexasHoldemService.Response.Builder r =  com.TexasHoldem.RpcInterface.rpc.TexasHoldemService.Response.newBuilder();
		r.setRetcode(1);
		return r.build();
	}
	@Override
	public Response tableStop(RpcController controller, TableConfgData request)
			throws ServiceException {
		// TODO Auto-generated method stub
		if(this.tablelist.containsKey(request.getTableid()))
			this.tablelist.get(request.getTableid()).setBstart(false);
		com.TexasHoldem.RpcInterface.rpc.TexasHoldemService.Response.Builder r =  com.TexasHoldem.RpcInterface.rpc.TexasHoldemService.Response.newBuilder();
		r.setRetcode(1);
		return r.build();
	}
	@Override
	public Response setTableBigBlind(RpcController controller,
			TableConfgData request) throws ServiceException {
		// TODO Auto-generated method stub
		if(this.tablelist.containsKey(request.getTableid()))
			this.tablelist.get(request.getTableid()).getTableCofing().setBigBlind(request.getSetbigblind());
		com.TexasHoldem.RpcInterface.rpc.TexasHoldemService.Response.Builder r =  com.TexasHoldem.RpcInterface.rpc.TexasHoldemService.Response.newBuilder();
		r.setRetcode(1);
		return r.build();
	}
	@Override
	public Response setTableBigBlindUpdTime(RpcController controller,
			TableConfgData request) throws ServiceException {
		// TODO Auto-generated method stub
		if(this.tablelist.containsKey(request.getTableid()))
			this.tablelist.get(request.getTableid()).getTableCofing().setBigBlind(request.getSetbigblind());
		com.TexasHoldem.RpcInterface.rpc.TexasHoldemService.Response.Builder r =  com.TexasHoldem.RpcInterface.rpc.TexasHoldemService.Response.newBuilder();
		r.setRetcode(1);
		return r.build();
	}
	@Override
	public Response setTableWaitBetTime(RpcController controller,
			TableConfgData request) throws ServiceException {
		// TODO Auto-generated method stub
		
		if(this.tablelist.containsKey(request.getTableid()))
			this.tablelist.get(request.getTableid()).getTableCofing().setBetTimeOut(request.getSetwaitbettime());
		com.TexasHoldem.RpcInterface.rpc.TexasHoldemService.Response.Builder r =  com.TexasHoldem.RpcInterface.rpc.TexasHoldemService.Response.newBuilder();
		r.setRetcode(1);
		return r.build();
	}
	@Override
	public PlayersList getTablePlayerInfo(RpcController controller,
			TableConfgData request) throws ServiceException {
		// TODO Auto-generated method stub
		TexasHoldemService.PlayersList.Builder data = TexasHoldemService.PlayersList.newBuilder();
		if(this.tablelist.containsKey(request.getTableid()))
		{
			for(Player p:this.tablelist.get(request.getTableid()).getPlayers().values())
			{
				PlayerData.Builder pd = PlayerData.newBuilder();
				pd.setCash(p.getCash());
				pd.setPlayerid(p.getClient().getId());
				pd.setName(p.getName());
				pd.setTableid(request.getTableid());
				data.addList(pd);
				
			}
		}
		return data.build();
	}
	@Override
	public Response setTableToken(RpcController controller,
			TableConfgData request) throws ServiceException {
		// TODO Auto-generated method stub
		if(this.tablelist.containsKey(request.getTableid()))
			this.tablelist.get(request.getTableid()).getTableCofing().setToken(request.getSettabletoken());
		com.TexasHoldem.RpcInterface.rpc.TexasHoldemService.Response.Builder r =  com.TexasHoldem.RpcInterface.rpc.TexasHoldemService.Response.newBuilder();
		r.setRetcode(1);
		return r.build();
	}
	@Override
	public Response playerNetException(RpcController controller,
			NotifyMsg request) throws ServiceException {
		// TODO Auto-generated method stub
		System.out.print(request.getMsg());
		PokerPlayer p = findbychannel(((SocketRpcController)controller).getChannel());
		if(p.getCurplaytable() != null)
		{
			for(Integer tableid:p.getCurplaytable().keySet())
			{
				Player player = p.getCurplaytable().get(tableid);
				if(player != null && this.tablelist.containsKey(tableid))
					this.tablelist.get(tableid).removePlayer(player);
				
				this.tablelist.get(tableid).notifyPlayerLeaveTable(player);
				
			}
			
		}
		return null;
	}
	@Override
	public Response heartActive(RpcController controller, Heart request)
			throws ServiceException {
		// TODO Auto-generated method stub
		
		//System.out.print(String.format("server heartActive:%d\n",System.currentTimeMillis()));
		return null;
	}
	@Override
	public Response getQuest(RpcController controller,QuestRequest request)
			throws ServiceException
	{
		// TODO Auto-generated method stub
		
		TexasHoldemService.QuestList.Builder questlist = TexasHoldemService.QuestList.newBuilder();

		PokerPlayer p = findbychannel(((SocketRpcController)controller).getChannel());
		
		if(p != null)
		{
			for(PokerQuest pq :p.getCurpokerqust())
			{
				pq.toQuest(questlist);
			}
		}
        
        BlockingRpcChannel blockchannel = RpcChannels.newBlockingRpcChannel(((SocketRpcController)controller).getChannel());
        
        com.TexasHoldem.RpcInterface.rpc.TexasHoldemService.TexasHoldemClient.BlockingInterface service = TexasHoldemService.TexasHoldemClient.newBlockingStub(blockchannel);
        
        try 
        {
       	 	Response Response = service.playerQuest(controller, questlist.build());
       	 
		}
        catch (ServiceException e) 
		{
				// TODO Auto-generated catch block
        	e.printStackTrace();
		}

		return null;
	}
	@Override
	public  void PutPlayerToFreeQueue(Player player) {
		// TODO Auto-generated method stub
		

		logger.debug("PutPlayerToFreeTable " + player);
		
		this.freePlayer.offer(player);


	}
	@Override
	public Collection<Player> GetPlayerFromFreeQueue(int getmax)
	{
		// TODO Auto-generated method stub
		List<Player> getlist = null;
		if(!this.freePlayer.isEmpty())
		{
			getlist = new ArrayList<Player>();
			Player player = this.freePlayer.poll();
			int getcount = 0;
			while(player != null)
			{
				if(getcount < getmax)
				{
					getlist.add(player);
					getcount++;
				}
				else
					break;
				player = this.freePlayer.poll();
			}
			
			
		}
		return getlist;
	}

	@Override
	public void OnDisConnect(Player player)
	{
		// TODO Auto-generated method stub
		
		
	}
	@Override
	public Response questAward(RpcController controller,QuestRequest request)
			throws ServiceException
	{
		// TODO Auto-generated method stub
		
		PokerPlayer p = findbychannel(((SocketRpcController)controller).getChannel());
		
		
		if(p != null)
		{
			for(PokerQuest pq :p.getCurpokerqust())
			{
				pq.OnFinish(request.getQuestId(), request.getQuestAwardparam());
			}
		}
		
		return null;
	}

	
	
}
